package websphinx;

import java.util.Vector;

public class MatchScript {

	// state takes on one of the following values:
	private static final int START = 0;
	private static final int ENTITY = 1;
	private static final int LT = 2;
	private static final int STAG = 3;
	private static final int ETAG = 4;
	private static final int ATTR = 5;
	private static final int ATTRNAME = 6;
	private static final int AFTEREQ = 7;
	private static final int ATTRVALUE = 8;
	private static final int CUSTOMED = 9;
	private static final int SCUS = 10;
	private static final int ECUS = 11;

	private String script = null;
	Vector tags = new Vector();
	Vector actions = new Vector();

	public MatchScript(String script) {
		this.script = script;
		if (script != null)
			tokenize();
	}

	@SuppressWarnings("unchecked")
	public Vector generateActions() {
		int deep = 0;
		for (int i = 0; i < tags.size(); i++) {
			Vector tokens = (Vector) tags.elementAt(i);
			String type = (String) tokens.elementAt(0);
			String tagName = (String) tokens.elementAt(1);
			Vector attrs = new Vector();
			if (tokens.size() > 2) {
				for (int j = 2; j < tokens.size(); j++)
					attrs.add(tokens.elementAt(j));
			}
			if (type.equals("STAG")) {
				if (deep == 0) {
					actions.add(new MatchStartTag(tagName, attrs));
				} else {
					actions.add(new MatchChildTag(tagName, attrs));
				}
				deep++;
			} else if (type.equals("ETAG")) {
				actions.add(new MatchCloseTag(tagName));
				deep--;
			} else if (type.equals("VALUE")) {
				actions.add(new MatchGetValue(tagName));
			} else if (type.equals("SCUS")) {
				if (tagName.equals("repeat")) {
					actions.add(new MatchStartRepeat(tagName));
				}
			} else if (type.equals("ECUS")) {
				if (tagName.equals("repeat")) {
					actions.add(new MatchCloseRepeat(tagName));
				}
			}
		}

		return this.actions;
	}

	@SuppressWarnings("unchecked")
	private void tokenize() {
		int state = START;

		// action list
		// Vector actions = new Vector();
		tags.clear();
		char[] buf = script.toCharArray();
		int scriptLen = script.length();
		int bufptr = 0;

		StringBuffer tagName = new StringBuffer();
		StringBuffer entity = new StringBuffer();
		StringBuffer attrName = new StringBuffer();
		StringBuffer attrValue = new StringBuffer();
		Vector attributes = new Vector();

		while (bufptr < scriptLen) {
			char c = (char) buf[bufptr];

			// System.err.println ("%% state == " + state + ", ptr == " +
			// (bufbase+bufptr) + ", c == " + c);

			switch (state) {
			case START:
				// after whitespace or tag
				switch (c) {
				case '<':
					++bufptr;
					state = LT;
					break;
				case ' ':
				case '\t':
				case '\n':
				case '\r':
					++bufptr;
					break;
				case '#':
					++bufptr;
					entity.setLength(0);
					state = ENTITY;
					break;
				case '(':
					++bufptr;
					tagName.setLength(0);
					state = CUSTOMED;
					break;
				default:
					++bufptr;
					break;
				}
				break;

			case LT:
				switch (c) {
				case '/':
					++bufptr;
					tagName.setLength(0);
					state = ETAG;
					break;
				default:
					state = STAG;
					attributes.clear();
					tagName.setLength(0);
					break;
				}
				break;

			case ENTITY:
				if (Character.isWhitespace(c)) {
					Vector tokens = new Vector();
					tokens.add("VALUE");
					tokens.add(entity.toString().trim());
					tags.add(tokens);
					state = START;
				} else {
					entity.append(c);
					++bufptr;
				}
				break;

			// Tags
			case STAG:
				if (c == '>') {
					Vector tokens = new Vector();
					tokens.add("STAG");
					tokens.add(tagName.toString().trim());
					for (int i = 0; i < attributes.size(); i++) {
						tokens.add(attributes.elementAt(i));
					}

					tags.add(tokens);
					state = START;

				} else if (Character.isWhitespace(c)) { // attributes
					attrName.setLength(0);
					attrValue.setLength(0);
					state = ATTR;
				} else {
					tagName.append(c);
					++bufptr;
				}
				break;

			case ETAG:
				if (c == '>') {
					Vector tokens = new Vector();
					tokens.add("ETAG");
					tokens.add(tagName.toString().trim());
					tags.add(tokens);
					state = START;
				} else {
					tagName.append(c);
					++bufptr;
				}
				break;

			case ATTR:
				if (Character.isWhitespace(c)) {
					++bufptr;
				} else if (c == '>') {
					state = STAG;
				} else {
					state = ATTRNAME;
				}
				break;

			case ATTRNAME:
				if (Character.isWhitespace(c)) {
					++bufptr;
				} else if (c == '=') {
					++bufptr;
					attributes.add(attrName.toString());
					attrName.setLength(0);
					state = AFTEREQ;
				} else {
					attrName.append(c);
					++bufptr;
				}
				break;

			case AFTEREQ:
				if (Character.isWhitespace(c)) {
					++bufptr;
				} else {
					state = ATTRVALUE;
				}
				break;

			case ATTRVALUE:
				if (Character.isWhitespace(c) || c == '>') {
					attributes.add(attrValue.toString());
					attrValue.setLength(0);
					state = ATTR;
				} else {
					attrValue.append(c);
					++bufptr;
				}
				break;

			case CUSTOMED:
				if(c=='/'){
					state = ECUS; 
					++bufptr;
				}else{
					state = SCUS; 
				}
				break;
					
			case SCUS:
				if(c == ')'){
					Vector tokens = new Vector();
					tokens.add("SCUS");
					tokens.add(tagName.toString().trim());
					tags.add(tokens);
					state = START;
				}else{
					tagName.append(c); 
					++bufptr; 
				}
				break;
					
			case ECUS:
				if(c == ')'){
					Vector tokens = new Vector();
					tokens.add("ECUS");
					tokens.add(tagName.toString().trim());
					tags.add(tokens);
					state = START;
				}else{
					tagName.append(c); 
					++bufptr; 
				}
				break;

			default:
				throw new RuntimeException(
						"HtmlTokenizer entered illegal state " + state);
			}
		}

	}

	public static void main(String[] args) {
		String script = new String(
				"<div id = m> <p> #pContent </p> (repeat)<p> #divContent <p> (/repeat)  </div>");

		MatchScript matchScript = new MatchScript(script);
		Vector result = matchScript.generateActions();

		for (int i = 0; i < result.size(); i++) {
			System.out.println(result.get(i).toString());
		}
	}
}
